<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0"/>
    <style>
        body{margin:0;padding:0;overflow: hidden;}
    </style>
    <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="icon.svg">
    <title>放烟花</title>
</head>
<body>

<div style="height:700px;overflow:hidden;">
    <canvas id='cas' style="background-color:rgba(0,5,24,1);">浏览器不支持canvas</canvas>
    <img src="moon.png" alt="" id="moon" style="visibility: hidden;"/>
</div>
<script>
    const canvas = document.getElementById("cas");
    const ocas = document.createElement("canvas");
    const octx = ocas.getContext("2d");
    const ctx = canvas.getContext("2d");
    ocas.width = canvas.width = window.innerWidth;
    ocas.height = canvas.height = 700;
    const bigbooms = [];

    window.onload = function(){
        initAnimate()
    }

    let lastTime;

    function initAnimate(){
        drawBg();

        lastTime = new Date();
        animate();
    }

    const raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); };

    const Boom = function(x,r,c,boomArea,shape){
        this.booms = [];
        this.x = x;
        this.y = (canvas.height+r);
        this.r = r;
        this.c = c;
        this.shape = shape || false;
        this.boomArea = boomArea;
        this.dead = false;
        this.ba = parseInt(getRandom(80 , 200));
        this.pow = new Audio("pow.ogg")
    };

    const stars=[];

    function animate(){
        let bigboom;
        ctx.save();
        ctx.fillStyle = "rgba(0,5,24,0.1)";
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.restore();


        const newTime = new Date();
        if(newTime-lastTime>500+(window.innerHeight-767)/2){
            const random = Math.random() * 100 > 2;
            const x = getRandom(canvas.width / 5, canvas.width * 4 / 5);
            const y = getRandom(50, 200);
            if(random){
                bigboom = new Boom(getRandom(canvas.width/3,canvas.width*2/3) ,2,"#FFF" , {x:x , y:y});
                bigbooms.push(bigboom)
            }
            else {
                bigboom = new Boom(getRandom(canvas.width / 3, canvas.width * 2 / 3), 2, "#FFF", {
                    x: canvas.width / 2,
                    y: 200
                }, document.querySelectorAll(".shape")[parseInt(getRandom(0, document.querySelectorAll(".shape").length))]);
                bigbooms.push(bigboom)
            }
            lastTime = newTime;
        }

        stars.foreach(function(){
            this.paint();
        })

        drawMoon();

        bigbooms.foreach(function(){
            const that = this;
            if(!this.dead){
                this._move();
                this._drawLight();
            }
            else{
                this.booms.foreach(function(index){
                    if(!this.dead) {
                        this.moveTo();
                    }
                    else if(index === that.booms.length-1){
                        bigbooms[bigbooms.indexOf(that)] = null;
                    }
                })
            }
        });

        raf(animate);
    }

    function drawMoon(){
        const moon = document.getElementById("moon");
        const centerX = canvas.width - 200, centerY = 100, width = 80;
        if(moon.complete){
            ctx.drawImage(moon , centerX , centerY , width , width )
        }
        else {
            moon.onload = function(){
                ctx.drawImage(moon ,centerX , centerY , width , width)
            }
        }
        let index = 0;
        for(let i=0; i<10; i++){
            ctx.save();
            ctx.beginPath();
            ctx.arc(centerX+width/2 , centerY+width/2 , width/2+index , 0 , 2*Math.PI);
            ctx.fillStyle="rgba(240,219,120,0.005)";
            index+=2;
            ctx.fill();
            ctx.restore();
        }

    }

    Array.prototype.foreach = function(callback){
        for(let i=0; i<this.length; i++){
            if(this[i]!==null) callback.apply(this[i] , [i])
        }
    }

    canvas.onclick = function(){
        const x = event.clientX;
        const y = event.clientY;
        const bigboom = new Boom(getRandom(canvas.width / 3, canvas.width * 2 / 3), 2, "#FFF", {x: x, y: y});
        bigbooms.push(bigboom)
    }
    const Frag = function(centerX , centerY , radius , color , tx , ty){
        this.tx = tx;
        this.ty = ty;
        this.x = centerX;
        this.y = centerY;
        this.dead = false;
        this.centerX = centerX;
        this.centerY = centerY;
        this.radius = radius;
        this.color = color;
    };
    Boom.prototype = {
        _paint:function(){
            ctx.save();
            ctx.beginPath();
            ctx.arc(this.x,this.y,this.r,0,2*Math.PI);
            ctx.fillStyle = this.c;
            ctx.fill();
            ctx.restore();
        },
        _move:function(){
            var dx = this.boomArea.x - this.x , dy = this.boomArea.y - this.y;
            this.x = this.x+dx*0.01;
            this.y = this.y+dy*0.01;

            if(Math.abs(dx)<=this.ba && Math.abs(dy)<=this.ba){
               this._boom();
               this.dead = true;
            }
            else {
                this._paint();
            }
        },
        _drawLight:function(){
            ctx.save();
            ctx.fillStyle = "rgba(255,228,150,0.3)";
            ctx.beginPath();
            ctx.arc(this.x , this.y , this.r+3*Math.random()+1 , 0 , 2*Math.PI);
            ctx.fill();
            ctx.restore();
        },
        _boom:function(){
            const fragNum = getRandom(30, 200);
            const style = getRandom(0, 10) >= 5 ? 1 : 2;
            let color;
            this.pow.volume = 0.5
            this.pow.play()
            if(style===1){
                color = {
                    a:parseInt(getRandom(128,255)),
                    b:parseInt(getRandom(128,255)),
                    c:parseInt(getRandom(128,255))
                }
            }

            const fanwei = parseInt(getRandom(300, 400));
            for(let i=0; i<fragNum; i++){
                if(style===2){
                    color = {
                        a:parseInt(getRandom(128,255)),
                        b:parseInt(getRandom(128,255)),
                        c:parseInt(getRandom(128,255))
                    }
                }
                const a = getRandom(-Math.PI, Math.PI);
                const x = getRandom(0, fanwei) * Math.cos(a) + this.x;
                const y = getRandom(0, fanwei) * Math.sin(a) + this.y;
                const radius = getRandom(0, 2);
                const frag = new Frag(this.x, this.y, radius, color, x, y);
                this.booms.push(frag);
            }
        },

    }
    function getRandom(a , b){
        return Math.random()*(b-a)+a;
    }

    const maxRadius = 1;

    const Star = function(x, y, r){
        this.x = x;this.y=y;this.r=r;
    };

    function drawBg(){
        for(let i=0; i<100; i++){
            const r = Math.random() * maxRadius;
            const x = Math.random() * canvas.width;
            const y = Math.random() * 2 * canvas.height - canvas.height;
            const star = new Star(x, y, r);
            stars.push(star);
            star.paint()
        }

    }

    Star.prototype = {
        paint:function(){
            ctx.save();
            ctx.beginPath();
            ctx.arc(this.x , this.y , this.r , 0 , 2*Math.PI);
            ctx.fillStyle = "rgba(255,255,255,"+this.r+")";
            ctx.fill();
            ctx.restore();
        }
    }
    Frag.prototype = {
        paint:function(){
            ctx.save();
            ctx.beginPath();
            ctx.arc(this.x , this.y , this.radius , 0 , 2*Math.PI);
            ctx.fillStyle = "rgba("+this.color.a+","+this.color.b+","+this.color.c+",1)";
            ctx.fill()
            ctx.restore();
        },
        moveTo:function(){
            this.ty = this.ty+0.3;
            const dx = this.tx - this.x, dy = this.ty - this.y;
            this.x = Math.abs(dx)<0.1 ? this.tx : (this.x+dx*0.1);
            this.y = Math.abs(dy)<0.1 ? this.ty : (this.y+dy*0.1);
            if(dx===0 && Math.abs(dy)<=80){
                this.dead = true;
            }
            this.paint();
        }
    }
</script>

</body>
</html>
